package vns.server;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import vns.client.service.ObjectPropertyService;
import vns.server.domain.Object;
import vns.server.domain.ObjectProperty;
import vns.server.domain.ObjectPropertyType;
import vns.server.domain.ObjectType;
import vns.server.domain.ObjectValue;
import vns.shared.ObjectDTO;
import vns.shared.ObjectPropertyDTO;
import vns.shared.ObjectPropertyTypeDTO;
import vns.shared.ObjectTypeDTO;
import vns.shared.ObjectValueDTO;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class ObjectPropertyServiceImpl extends RemoteServiceServlet implements
		ObjectPropertyService {

	@Override
	public ObjectPropertyDTO Create(ObjectPropertyDTO opropertyDTO) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		ObjectProperty action = null;
		try {
			action = new ObjectProperty(opropertyDTO);
			pm.makePersistent(action);
		} finally {
			pm.close();
		}
		return action.toDTO();
	}

	@Override
	public boolean Remove(Key id) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			ObjectProperty action = pm.getObjectById(ObjectProperty.class, id);
			if (action != null) {
				pm.deletePersistent(pm.getObjectById(ObjectProperty.class, id));
			}

		} finally {
			pm.close();
		}
		return true;
	}

	@Override
	public ObjectPropertyDTO Loadbyid(Key id) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		ObjectPropertyDTO actionDTO = null;
		try {
			ObjectProperty action = pm.getObjectById(ObjectProperty.class, id);
			actionDTO = action.toDTO();
		} finally {
			pm.close();
		}
		return actionDTO;
	}

	@Override
	public ObjectPropertyDTO Update(ObjectPropertyDTO opropertyDTO) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		ObjectProperty action = null;
		try {
			action = pm.getObjectById(ObjectProperty.class,
					opropertyDTO.getId());
			action.updateFromDTO(opropertyDTO);
		} finally {
			pm.close();
		}

		return action.toDTO();
	}

	@Override
	public ArrayList<ObjectPropertyDTO> Loadall(ObjectPropertyTypeDTO optypeDTO) {
		// khong su dung
		
		ArrayList<ObjectPropertyDTO> listactionDTO = new ArrayList<ObjectPropertyDTO>();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		String temp = KeyFactory.keyToString(optypeDTO.getId());
		Query q = pm.newQuery(ObjectProperty.class);
		q.setFilter("optype == Optype");
		q.setOrdering("weight asc");
		q.declareParameters("String Optype");
		try {
			List<ObjectProperty> actions = (List<ObjectProperty>) q
					.execute(temp);
			for (ObjectProperty action : actions) {
				listactionDTO.add(pm
						.getObjectById(ObjectProperty.class, action).toDTO());
			}
		} finally {
			pm.close();
		}
		return listactionDTO;
	}

	@Override
	public ArrayList<ObjectPropertyDTO> Loadall(ObjectTypeDTO otypeDTO) {
		ArrayList<ObjectPropertyDTO> listactionDTO = new ArrayList<ObjectPropertyDTO>();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		String temp = KeyFactory.keyToString(otypeDTO.getId());
		Query q = pm.newQuery(ObjectProperty.class);
		q.setFilter("objecttype == otypeparam");
		q.setOrdering("weight asc");
		q.declareParameters("String otypeparam");
		try {
			if (temp != null && temp != "") {
				@SuppressWarnings("unchecked")
				List<ObjectProperty> actions = (List<ObjectProperty>) q
						.execute(temp);
				// .execute();
				for (ObjectProperty action : actions) {
					ObjectPropertyDTO opDTO = action.toDTO();
					if (action.getOptype() != null && action.getOptype() != "") {
						ObjectPropertyType opt = pm.getObjectById(
								ObjectPropertyType.class,
								KeyFactory.stringToKey(action.getOptype()));
						opDTO.setOptypename(opt.getBaseType());
						
						if (opt.getObjecttype() != null
								&& !opt.getObjecttype().equals("")) {
							//
							// Set Object Type Name
							//
							ObjectType ot = pm
									.getObjectById(ObjectType.class, KeyFactory
											.stringToKey(opt.getObjecttype()));
							opDTO.setObjtypename(ot.getName());

						
							//
							// Set Object Related List in Key Type
							// 
							Query q4 = pm.newQuery(Object.class);
							q4.setFilter("otype == otype3param");
							q4.declareParameters("String otype3param");
							@SuppressWarnings("unchecked")
							List<Object> listORelated = (List<Object>) q4.execute(opt.getObjecttype());
							List<ObjectDTO> listORelatedDTO = new ArrayList<ObjectDTO>();
							for(Object oRelated : listORelated){
								ObjectDTO oRelatedDTO = oRelated.toDTO();
								
								
								
								
								Query q2 = pm.newQuery(ObjectProperty.class);
								q2.setFilter("objecttype == otype2param");
								q2.declareParameters("String otype2param");
								List<ObjectProperty> listProperty = (List<ObjectProperty>) q2
										.execute(oRelatedDTO.getOtype());
								for (ObjectProperty op : listProperty) {
									
									
									
									if (op.getMain()) {
										ObjectPropertyDTO opDTO2 = op.toDTO();
										Query q3 = pm.newQuery(ObjectValue.class);
										q3.setFilter("objectKey == :okey && propertyKey == :pkey");
										q3.setUnique(true);
										ObjectValue value = (ObjectValue) q3.execute(
												KeyFactory.keyToString(oRelatedDTO.getId()),
												KeyFactory.keyToString(opDTO2.getId()));
										oRelatedDTO.setMain(value.getValue());
									}
									
								}
								
								
								
								
								
								
								listORelatedDTO.add(oRelatedDTO);
							}
							opDTO.setlistObjectRelated(listORelatedDTO);
						
						}
						
					}

					listactionDTO.add(opDTO);
				}
			}
		} finally {
			q.closeAll();
			pm.close();
		}
		return listactionDTO;
	}

	@Override
	public List<ObjectPropertyDTO> loadall() {
		List<ObjectPropertyDTO> listactionDTO = new ArrayList<ObjectPropertyDTO>();

		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query q = pm.newQuery(ObjectProperty.class);
		try {
			@SuppressWarnings("unchecked")
			List<ObjectProperty> res = (List<ObjectProperty>) q.execute();
			for (ObjectProperty actiontype : res) {
				ObjectProperty term = pm.detachCopy(actiontype);
				listactionDTO.add(term.toDTO());
			}
		} finally {
			pm.close();
		}
		return listactionDTO;
	}

	@Override
	public void updateall(List<ObjectPropertyDTO> listnew) {
		List<ObjectPropertyDTO> listOld = this.loadall();
		for (ObjectPropertyDTO element : listnew) {
			if (!containInList(listOld,element)) {
				this.Create(element);
			} else {
				this.Update(element);
			}
		}
		for (ObjectPropertyDTO element : listOld) {
			if (!containInList(listnew,element)) {
				this.Remove(element.getId());
			}
		}
	}

	@Override
	public void Updateall(List<ObjectPropertyDTO> listNew,
			ObjectPropertyTypeDTO optypeDTO) {

	}

	@SuppressWarnings("unchecked")
	@Override
	public void Updateall(List<ObjectPropertyDTO> listNew,
			ObjectTypeDTO otypeDTO) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		List<ObjectPropertyDTO> listOld = this.Loadall(otypeDTO);
		try {
			for (ObjectPropertyDTO element : listNew) {
				if (!containInList(listOld,element)) {
					element = this.Create(element);
				} else {
					this.Update(element);
				}
			}
			for (ObjectPropertyDTO element : listOld) {
				if (!containInList(listNew,element)) {
					Query q = pm.newQuery(ObjectValue.class);
					q.setFilter("propertyKey==:opkey");
					List<ObjectValue> list = (List<ObjectValue>) q
							.execute(element.getObjecttype());
					pm.deletePersistentAll(list);
					this.Remove(element.getId());
				}
			}

		} finally {
			pm.close();
		}
	}

	private boolean containInList(List<ObjectPropertyDTO> list,
			ObjectPropertyDTO element) {
		if (element.getId() == null)
			return false;
		for (ObjectPropertyDTO opDTO : list) {
			if (opDTO.getId().equals(element.getId()))
				return true;
		}
		return false;
	}
}
